/**
 * 
 */
package com.cipe.cmrs.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.cipe.cmrs.bean.PaymentRequestBean;
import com.cipe.cmrs.bean.PaymentRequestLineItemBean;
import com.cipe.cmrs.helper.PaymentHelper;
import com.cipe.cmrs.model.AccountCode;
import com.cipe.cmrs.model.Cipeproject;
import com.cipe.cmrs.model.Paymentrequest;
import com.cipe.cmrs.model.Paymentrequestlineitem;
import com.cipe.cmrs.model.Paymenttype;
import com.cipe.cmrs.model.User;
import com.cipe.cmrs.util.DateUtil;
import com.cipe.cmrs.util.DateUtil2;
import com.cipe.cmrs.util.NumberUtil;
import com.cipe.cmrs.util.Util;

/**
 * @author Incepio
 * 
 */
@Service
@Transactional
public class PaymentrequestService extends BaseService<Paymentrequest> {

    @Autowired
    private UserService userService;
    @Autowired
    private ConversionService conversionService;
    @Autowired
    private PaymentrequestlineitemService paymentrequestlineitemService;
    @Autowired
    private PaymentHelper paymentService;

    public List<Paymentrequest> findPaymentrequest(Paymentrequest paymentrequest) {
        // Object[] params = { paymentrequest.getPaymentIdentifiedInformation(),
        // paymentrequest.getPayee().getId() };
        List<Paymentrequest> paymentrequestList = new ArrayList<Paymentrequest>();
        try {
            // FIXME create query
        	String query = "";
        	if((paymentrequest.getCostcenternumber()!=null && !"".equals(paymentrequest.getCostcenternumber()) ) || paymentrequest.getAccountcode()!=null && paymentrequest.getAccountcode().getId()!=null){
                query = " select distinct  req.id from Paymentrequest as req left join req.paymentrequestlineitems as item where ";
        	 } else {
        		 query = " select distinct  req.id from Paymentrequest as req  where "; 
        	 }
        	 query=query + Util.createFirstQueryClauseIntvalue("req.id", paymentrequest.getPaymentIdentifiedInformation());
                if(paymentrequest.getPayee()!=null)
                	query = query + Util.createQueryClause("req.payee.id", paymentrequest.getPayee().getId());
                if(paymentrequest.getPaymentmethod()!=null)
                	query = query  + Util.createQueryClause("req.paymentmethod", paymentrequest.getPaymentmethod());
                if(paymentrequest.getAccountcode()!=null)	
                	query = query +	 Util.createQueryClause("item.accountCode.id",paymentrequest.getAccountcode().getId());
                
                if(paymentrequest.getCostcenternumber()!=null && !"".equals(paymentrequest.getCostcenternumber()))	
                	query = query +	 Util.createlikeQueryClause("item.cipeproject.costCenterNumber",paymentrequest.getCostcenternumber());
                
              //  System.out.println("payment request id..." + paymentrequest.getPaymentmethod());
              //  System.out.println("payment request id..." + paymentrequest.getStartAmount());
                if(paymentrequest.getPaymentmethod()!=null && "".equals(paymentrequest.getPaymentmethod()))
                	query = query + Util.createQueryClause("req.paymentmethod", paymentrequest.getPaymentmethod());
                
                if(paymentrequest.getStatusCode()!=null)
                	query = query + Util.createQueryClause("req.statusCode", paymentrequest.getStatusCode());
                if(paymentrequest.getCreatedBy()!=null)
                	query = query +Util.createQueryClause("req.createdBy", paymentrequest.getCreatedBy().getId());
                if(paymentrequest.getStartDate()!=null)
                	query = query + Util.createRangeQueryClause("req.invoiceRequestDate", paymentrequest.getStartDate(), paymentrequest.getEndDate());
                if(paymentrequest.getStartDate()!=null)
                	query = query +	Util.createRangeQueryClause("req.invoiceRequestDate", paymentrequest.getStartDate(), paymentrequest.getEndDate());
                if(paymentrequest.getStartAmount()!=null)
                	query = query + Util.createRangeQueryClause("req.amount", paymentrequest.getStartAmount(), paymentrequest.getEndAmount());
                if(paymentrequest.getPaymenttype()!=null)
                	query = query +Util.createQueryClause("req.paymenttype.id", paymentrequest.getPaymenttype().getId());
              //  + Util.createRangeQueryClause("req.invoiceRequestDate", paymentrequest.getStartDate(), paymentrequest.getEndDate())
              //  + Util.createRangeQueryClause("req.amount", paymentrequest.getStartAmount(), paymentrequest.getEndAmount())
              //  + Util.createQueryClause("req.paymenttype.id", paymentrequest.getPaymenttype().getId())
                String query1 = "select distinct rq1 from  Paymentrequest as rq1 where rq1.id in ("+query+") ";  
                query1 = query1  + Util.createOrderByAsc("rq1.id");
                
            logger.error("QUERY:" + query1);
            System.out.println(query);
           if(paymentrequest.getStartDate()!=null){
        	   String [] params = new String[2];
        	   params[0]="startDate";
        	   params[1]="endDate";
        	    Object [] parameters = new Object[2];
        	    parameters[0] = paymentrequest.getStartDate();
        	    parameters[1] = paymentrequest.getEndDate();
        	    
        	   paymentrequestList = dao.getResultParameter(query1, Paymentrequest.class, params, parameters);   
           } else
           {
               paymentrequestList = dao.getResultList(query1);
           }
            
            /*
             * paymentrequestList = dao.getNamedQueryResultList(
             * "findPaymentrequest", params);
             */
        } catch (Exception exp) {
            logger.warn(exp.toString());
        }
        return paymentrequestList;
    }

    /**
     * This method call the databse procedure and return the list
     * 
     * @param procedureName
     * @return
     */
    public List<Paymentrequest> findPaymentrequest(String procedureName) {
        return this.dao.getResultListWithNativeQuery(procedureName, Paymentrequest.class);
    }

    public PaymentRequestBean rejectPaymentRequest(PaymentRequestBean bean, Integer userId) {
        bean.setStatusCode(getText("status.payment.process.rejected"));
        bean.setDateRejected(new Date());
        User user = userService.findById(userId);
        bean.setUser(user);
        bean.setCurrentlyresponsible(user.getFullName());
        merge(conversionService.convert(bean, Paymentrequest.class));
        return bean;
    }

    public PaymentRequestBean cancelPaymentRequest(PaymentRequestBean bean, Integer userId, String personResponsible) {
        bean.setStatusCode(getText("status.payment.process.cancelled"));
        bean.setDateCancelled(new Date());
        bean.setCurrentlyresponsible(personResponsible);
        User user = userService.findById(userId);
        bean.setUser(user);
        merge(conversionService.convert(bean, Paymentrequest.class));
        return bean;
    }

    public PaymentRequestBean forwardToFinance(PaymentRequestBean bean, Integer userId) {
        bean.setStatusCode(getText("status.payment.process.finance"));
        bean.setCurrentlyresponsible(getText("status.responsible.payment.process.financeassistant"));
        bean.setDateToFinanace(new Date());
        merge(conversionService.convert(bean, Paymentrequest.class));
        return bean;
    }

    public PaymentRequestBean processPaymentRequest(PaymentRequestBean bean, Integer userId) {
        if (getText("status.payment.process.new").equals(bean.getStatusCode())
            || getText("status.payment.process.resubmitted").equals(bean.getStatusCode())) {
            bean.setStatusCode(getText("status.payment.process.finance"));
            bean.setCurrentlyresponsible(getText("status.responsible.payment.process.financeassistant"));
            bean.setDateToFinanace(new Date());
        } else if (getText("status.payment.process.finance").equals(bean.getStatusCode())) {
            bean.setStatusCode(getText("status.payment.process.signature"));
            bean.setDateforwardedforsignature(new Date());
            bean.setCurrentlyresponsible(getText("status.responsible.payment.process.signatories"));
        } else if (getText("status.payment.process.signature").equals(bean.getStatusCode())) {
            bean.setStatusCode(getText("status.payment.process.pendingpayment"));
            bean.setDatesubmittedforpayment(new Date());
            if ("check".equalsIgnoreCase(bean.getPaymentMethod())) {
                bean.setCurrentlyresponsible(getText("status.responsible.payment.process.outsideaccountant"));
            } else if ("wire".equalsIgnoreCase(bean.getPaymentMethod())) {
                if (bean.getAmount() == null || new BigDecimal("50000").compareTo(bean.getAmount()) > 0) {
                    bean.setCurrentlyresponsible(getText("status.responsible.payment.process.financemanager"));
                } else {
                    bean.setCurrentlyresponsible(getText("status.responsible.payment.process.deputydirector"));
                }
            }
        } else if (getText("status.payment.process.pendingpayment").equals(bean.getStatusCode())) {
            bean.setStatusCode(getText("status.payment.process.paid"));
            bean.setCurrentlyresponsible(getText("status.responsible.payment.process.financeassistant"));
            bean.setDatePaid(new Date());
        } else if (getText("status.payment.process.cancelrequested").equals(bean.getStatusCode())) {
            // paymentRequest.setCurrentlyresponsible(getText("status.responsible.payment.process.financeassistant"));
        }
        User user = userService.findById(userId);
        bean.setUser(user);
        merge(conversionService.convert(bean, Paymentrequest.class));
        return bean;
    }

    public PaymentRequestBean setCancelRequested(PaymentRequestBean bean, Integer userId) {
        bean.setDateCancelRequested(new Date());
        bean.setStatusCode(getText("status.payment.process.cancelrequested"));
        merge(conversionService.convert(bean, Paymentrequest.class));
        return bean;
    }

    public PaymentRequestBean resubmitPayment(PaymentRequestBean bean, Integer userId) {
        bean.setStatusCode(getText("status.payment.process.resubmitted"));
        bean.setCurrentlyresponsible(getText("status.responsible.payment.process.financeassistant"));
        bean.setDateResubmitted(new Date());
        merge(conversionService.convert(bean, Paymentrequest.class));
        return bean;
    }

    public Paymentrequest savePaymentrequest(Paymentrequest paymentrequest, Integer userId) {
        if (paymentrequest != null) {
            User user = userService.findById(userId);
            Paymentrequest dbPaymentrequest = findById(paymentrequest.getId());
            if (dbPaymentrequest == null) {
                dbPaymentrequest = new Paymentrequest();
                dbPaymentrequest.setCreatedBy(user);
                dbPaymentrequest.setCreationDate(DateUtil.getCurrentDate());
            } else {
                dbPaymentrequest.setUpdatedBy(user);
                dbPaymentrequest.setUpdationDate(DateUtil.getCurrentDate());
            }
            // setter
            Paymenttype paymentType = paymentrequest.getPaymenttype();
            if (paymentType.getId() != null && paymentType.getId() > 0) {
                dbPaymentrequest.setPaymenttype(paymentType);
            } else {
                dbPaymentrequest.setPaymenttype(null);
            }
            dbPaymentrequest.setPaymentIdentifiedInformation(paymentrequest.getPaymentIdentifiedInformation());
            dbPaymentrequest.setReceivedFromAccountingDate(paymentrequest.getReceivedFromAccountingDate());
            // dbPaymentrequest.setPaymentrequesttype(paymentrequest.getPaymentrequesttype());
            dbPaymentrequest.setPaymentmethod(paymentrequest.getPaymentmethod());
            dbPaymentrequest.setPayee(paymentrequest.getPayee());
            dbPaymentrequest.setPurposeOfExpenditure(paymentrequest.getPurposeOfExpenditure());
            dbPaymentrequest.setSpecialInstructions(paymentrequest.getSpecialInstructions());
            dbPaymentrequest.setInvoiceRequestDate(paymentrequest.getInvoiceRequestDate());
            dbPaymentrequest.setInvoicenumber(paymentrequest.getInvoicenumber());
            dbPaymentrequest.setDateToFinanace(paymentrequest.getDateToFinanace());
            dbPaymentrequest.setStatusCode(paymentrequest.getStatusCode());
            dbPaymentrequest.setAmount(paymentrequest.getAmount());
            dbPaymentrequest.setCurrentlyresponsible(paymentrequest.getCurrentlyresponsible());

            savePaymentLineItems(dbPaymentrequest, paymentrequest, user);

            dbPaymentrequest = merge(dbPaymentrequest);

            // Fix for 0131-95
            dbPaymentrequest.getLineItemBeans().clear();
            for (Paymentrequestlineitem item : dbPaymentrequest.getPaymentrequestlineitems()) {
                item.setLineitemnumber(item.getId());
                dbPaymentrequest.getLineItemBeans().add(conversionService.convert(item, PaymentRequestLineItemBean.class));
            }
            return dbPaymentrequest;
        }
        return null;
    }

    public PaymentRequestBean savePaymentrequest(PaymentRequestBean bean, Integer userId) {
        User user = userService.findById(userId);
        bean.setUser(user);
        Paymentrequest request = merge(conversionService.convert(bean, Paymentrequest.class));
        return conversionService.convert(request, PaymentRequestBean.class);
    }

    public PaymentRequestBean getPaymentRequestbean(Integer id) {
        return conversionService.convert(findById(id), PaymentRequestBean.class);
    }

    private void savePaymentLineItems(Paymentrequest dbPaymentrequest, Paymentrequest paymentRequestBean, User user) {
        Map<Integer, Paymentrequestlineitem> map = new HashMap<Integer, Paymentrequestlineitem>();

        List<Paymentrequestlineitem> list = dbPaymentrequest.getPaymentrequestlineitems();
        if (list == null) {
            list = new ArrayList<Paymentrequestlineitem>();
            dbPaymentrequest.setPaymentrequestlineitems(list);
        } else {
            for (Paymentrequestlineitem item : list) {
                map.put(item.getId(), item);
            }
        }

        for (PaymentRequestLineItemBean bean : paymentRequestBean.getLineItemBeans()) {
            if (paymentService.hasData(bean)) {
                Paymentrequestlineitem item = map.get(bean.getId());
                if (item == null) {
                    item = new Paymentrequestlineitem();
                    item.setCreatedBy(user);
                    item.setCreationDate(new Date());
                    list.add(item);
                } else {
                    item.setUpdatedBy(user);
                    item.setUpdationDate(new Date());
                    map.remove(bean.getId());
                }

                item.setPaymentrequest(dbPaymentrequest);

                if (bean.getAccountCodeId() != null) {
                    AccountCode accountCode = new AccountCode();
                    accountCode.setId(bean.getAccountCodeId());
                    item.setAccountCode(accountCode);
                } else {
                    item.setAccountCode(null);
                }
                if (bean.getCipeProjectId() != null) {
                    Cipeproject cipeProject = new Cipeproject();
                    cipeProject.setId(bean.getCipeProjectId());
                    item.setCipeproject(cipeProject);
                } else {
                    item.setCipeproject(null);
                }
                item.setPaymentrequestamount(bean.getAmount());
            }
        }

        for (Paymentrequestlineitem item : map.values()) {
            list.remove(item);
        }

        paymentrequestlineitemService.deleteAll(map.values());
    }

    @SuppressWarnings("rawtypes")
    // Fix for UAT-029 - Claris
    // System should not allow a new record to be added where a previously
    // entered record has the same values for 1) invoice number, 2) invoice
    // date, 3) payee and 4) amount (combination of all)
    public boolean isExisting(PaymentRequestBean bean) {
        if (!bean.getPrevInvoicenumber().equalsIgnoreCase(bean.getInvoicenumber())
            || !DateUtil2.INSTANCE.isSameDay(bean.getPrevInvoiceRequestDate(), bean.getInvoiceRequestDate())
            || !NumberUtil.INSTANCE.isEqual(bean.getPrevPayeeId(), bean.getPayeeId())
            || !NumberUtil.INSTANCE.isEqual(bean.getPrevAmount(), bean.getAmount())) {

            int counter = 1;
            List<Object> parameters = new ArrayList<Object>();
            StringBuilder whereBuilder = new StringBuilder();
            if (StringUtils.isNotBlank(bean.getInvoicenumber())) {
                whereBuilder.append("UPPER(obj.invoicenumber) = ?" + counter++);
				parameters.add(bean.getInvoicenumber().toUpperCase());
            } else {
                whereBuilder.append("(obj.invoicenumber IS NULL OR obj.invoicenumber = ?" + counter++ + ")");
                parameters.add("");
            }

            if (bean.getInvoiceRequestDate() != null) {
                whereBuilder.append(" AND obj.invoiceRequestDate BETWEEN ?" + counter++ + " AND ?" + counter++);
                parameters.add(DateUtil2.INSTANCE.getSodDate(bean.getInvoiceRequestDate()));
                parameters.add(DateUtil2.INSTANCE.getEodDate(bean.getInvoiceRequestDate()));
            } else {
                whereBuilder.append(" AND obj.invoiceRequestDate IS NULL");
            }

            if (bean.getPayeeId() != null && bean.getPayeeId() > 0) {
                whereBuilder.append(" AND obj.payee.id = ?" + counter++);
                parameters.add(bean.getPayeeId());
            } else {
                whereBuilder.append(" AND obj.payee IS NULL");
            }

            if (bean.getAmount() != null) {
                whereBuilder.append(" AND obj.amount = ?" + counter++);
                parameters.add(bean.getAmount());
            } else {
                whereBuilder.append(" AND obj.amount IS NULL");
            }
            
			if (bean.getId() != null && bean.getId() > 0) {
				whereBuilder.append(" AND obj.id != ?" + counter++);
				parameters.add(bean.getId());
			}

            String query = "SELECT COUNT(obj) FROM " + Paymentrequest.class.getName() + " obj WHERE " + whereBuilder.toString();
            List results = this.dao.getResultList(query, parameters.toArray(new Object[0]));
            Long total = results != null ? (Long) results.get(0) : 0L;
            return total != null && total > 0;
        } else {
            return false;
        }
    }

}
